package com.zhuangjie.mvc.aop;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhuangjie.mvc.annotation.ParamInject;
import org.springframework.core.MethodParameter;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Map;

public class ParamsInjectResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(ParamInject.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        // 通过反射来创建DTO对象
        Class<?> clazz = parameter.getParameterType();
        Object dto = clazz.newInstance();

        // 获取请求参数
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        Map<String, String[]> parameterMap = request.getParameterMap();
        // 创建ObjectMapper实例，它是所有Jackson库的中心类，提供了对象序列化和反序列化功能
        ObjectMapper objectMapper = new ObjectMapper();
        // 通过反射将请求参数值赋值给DTO对象
        for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
            String fieldName = entry.getKey();
            Field field = getFieldIncludingParentClasses(fieldName, clazz);
            String value = entry.getValue()[0];
            // 没有接收的属性，前端多传了，跳过
            if (field == null) {
                continue;
            }
            // 有属性，但如果value是无效的，那看一下这个属性是不是必要的，如果是，那就抛出异常
            if (value == null || value.indexOf("undefined") == 0) {
                if (field.getAnnotation(NotNull.class) != null) {
                    NotNull notNullAnnotation = field.getAnnotation(NotNull.class);
                    FieldError fieldError = new FieldError(clazz.getName(), fieldName, value, false, null, null, notNullAnnotation.message());
                    BindingResult bindingResult = new BeanPropertyBindingResult(dto, clazz.getName());
                    bindingResult.addError(fieldError);
                    throw new MethodArgumentNotValidException(parameter, bindingResult);
                }
                continue;
            }

            field.setAccessible(true);
            Class<?> fieldType = field.getType();
            // 根据字段的类型，进行对应的转换
            if (fieldType.equals(Integer.class) || fieldType.equals(int.class)) {
                field.set(dto, Integer.parseInt(value));
            } else if (fieldType.equals(Long.class) || fieldType.equals(long.class)) {
                field.set(dto, Long.parseLong(value));
            } else if (fieldType.equals(Double.class) || fieldType.equals(double.class)) {
                field.set(dto, Double.parseDouble(value));
            } else if (fieldType.equals(Float.class) || fieldType.equals(float.class)) {
                field.set(dto, Float.parseFloat(value));
            } else if (fieldType.equals(Boolean.class) || fieldType.equals(boolean.class)) {
                field.set(dto, Boolean.parseBoolean(value));
            } else if ((fieldType.equals(Date.class) || fieldType.equals(LocalDateTime.class)) && value instanceof String) {
                if (fieldType.equals(Date.class)) {
                    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    field.set(dto, formatter.parse(value));
                } else {
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                    field.set(dto, LocalDateTime.parse(value, formatter));
                }
            } else if (fieldType.equals(LocalDate.class) && value instanceof String) {
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                field.set(dto, LocalDate.parse(value, formatter));
            } else if (fieldType.equals(LocalTime.class) && value instanceof String) {
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
                field.set(dto, LocalTime.parse(value, formatter));
            } else if (value.startsWith("{") || value.startsWith("[")) {
                Object jsonValue = objectMapper.readValue(value, fieldType);
                field.set(dto, jsonValue);
            } else {
                // 对于其他类型，如果它不是上述的数值或布尔类型，假设它是字符串
                // 如果你有更多的类型需要处理，你可以在这里扩展你的逻辑
                try {
                    field.set(dto, value);
                } catch (Exception e) {
                }
            }

        }
        return dto;
    }

    private static Field getFieldIncludingParentClasses(String fieldName, Class<?> clazz) throws NoSuchFieldException {
        try {
            return clazz.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            Class<?> superclass = clazz.getSuperclass();
            if (superclass == null) {
                // 能到这一步说明已经到了最顶层的父类(Object类)，但还没找到字段，所以抛出异常
                return null;
            }
            // 在父类中递归查找
            return getFieldIncludingParentClasses(fieldName, superclass);
        }
    }
}
